#include "Meh.h"

// Author : d3c0mpil3r!
// Note: I'm lazy! :P

HMODULE dllHandle = NULL;
HANDLE hPipeSend = NULL;
HANDLE hPipeRecv = NULL;

// For Hooking.
BYTE x1, x2, x3, x4, x5;
DWORD y1, y2, y3, y4, y5;

fpMessageBoxW RealMBW = (fpMessageBoxW)GetProcAddress(GetModuleHandleA("user32.dll"), "MessageBoxW");
fpTerminateProcess RealTerminateProcess = (fpTerminateProcess)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtTerminateProcess");
fpCreateProcessW RealCreateProcess = (fpCreateProcessW)GetProcAddress(GetModuleHandleA("kernel32.dll"), "CreateProcessW");
fpWriteProcessMemory RealWPM = (fpWriteProcessMemory)GetProcAddress(GetModuleHandleA("kernel32.dll"), "WriteProcessMemory");
fpReadProcessMemory RealRPM = (fpReadProcessMemory)GetProcAddress(GetModuleHandleA("kernel32.dll"), "ReadProcessMemory");

// Stucture to hold our data!
DATA data;

void HookAPI(int x, LPVOID lpOld, LPVOID lpNew)
{
	DWORD old;
	VirtualProtect(lpOld, 5, PAGE_EXECUTE_READWRITE, &old);

	PBYTE a, b;
	a = (PBYTE)lpOld;
	b = (PBYTE)lpNew;
	
	switch (x)
	{
	case 1:
		x1 = *a;
		y1 = *((PDWORD)(a + 1));
		break;

	case 2:
		x2 = *a;
		y2 = *((PDWORD)(a + 1));
		break;

	case 3:
		x3 = *a;
		y3 = *((PDWORD)(a + 1));
		break;

	case 4:
		x4 = *a;
		y4 = *((PDWORD)(a + 1));
		break;

	case 5:
		x5 = *a;
		y5 = *((PDWORD)(a + 1));
		break;
	}

	*a = 0xE9;
	*((PDWORD)(a + 1)) = b - a - 5;

	VirtualProtect(lpOld, 5, old, &old);
}

void RepairAPI(int x, LPVOID lpAddress)
{
	DWORD old;
	VirtualProtect(lpAddress, 5, PAGE_EXECUTE_READWRITE, &old);
	
	switch (x)
	{
	case 1:
		*(PBYTE)lpAddress = x1;
		*((PDWORD)((PBYTE)lpAddress + 1)) = y1;
		break;

	case 2:
		*(PBYTE)lpAddress = x2;
		*((PDWORD)((PBYTE)lpAddress + 1)) = y2;
		break;

	case 3:
		*(PBYTE)lpAddress = x3;
		*((PDWORD)((PBYTE)lpAddress + 1)) = y3;
		break;

	case 4:
		*(PBYTE)lpAddress = x4;
		*((PDWORD)((PBYTE)lpAddress + 1)) = y4;
		break;

	case 5:
		*(PBYTE)lpAddress = x5;
		*((PDWORD)((PBYTE)lpAddress + 1)) = y5;
		break;
	}

	VirtualProtect(lpAddress, 5, old, &old);
}

// ReadProcessMemoey
BOOL WINAPI MyReadProcessMemory(
    __in      HANDLE hProcess,
    __in      LPCVOID lpBaseAddress,
    __out_bcount_part(nSize, *lpNumberOfBytesRead) LPVOID lpBuffer,
    __in      SIZE_T nSize,
    __out_opt SIZE_T * lpNumberOfBytesRead
    )
{
	int res = 0;

	SecureZeroMemory(&data, sizeof(data));

	strcpy(data.apiName, "ReadProcessMemory");

	char x[80] = { 0 };
	sprintf(x, "%x (Process handle)", hProcess);
	strcpy(data.msg1, x);

	sprintf(x, "%x (Base address)", lpBaseAddress);
	strcpy(data.msg2, x);

	strcpy(data.msg3, (char *)lpBuffer);
	strcat(data.msg3, " (Data read)");

	sprintf(x, "%u (Buffer size)", nSize);
	strcpy(data.msg4, x);

	sprintf(x, "%u (Bytes read)", &lpNumberOfBytesRead);
	strcpy(data.msg5, x);

	if (Confirm(data))
	{
		RepairAPI(5, RealRPM);
		res = RealRPM(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead);
		HookAPI(5, RealRPM, MyReadProcessMemory);
	}

	return res;
}

// WriteProcessMemory
BOOL WINAPI MyWriteProcessMemory(
    __in      HANDLE hProcess,
    __in      LPVOID lpBaseAddress,
    __in_bcount(nSize) LPCVOID lpBuffer,
    __in      SIZE_T nSize,
    __out_opt SIZE_T * lpNumberOfBytesWritten
    )
{
	int res = 0;

	SecureZeroMemory(&data, sizeof(data));

	strcpy(data.apiName, "WriteProcessMemory");

	char x[80] = { 0 };
	sprintf(x, "%x (Process handle)", hProcess);
	strcpy(data.msg1, x);

	sprintf(x, "%x (Base address)", lpBaseAddress);
	strcpy(data.msg2, x);

	strcpy(data.msg3, (char *)lpBuffer);
	strcat(data.msg3, " (Data written)");

	sprintf(x, "%u (Buffer size)", nSize);
	strcpy(data.msg4, x);

	sprintf(x, "%u (Bytes written)", &lpNumberOfBytesWritten);
	strcpy(data.msg5, x);

	if (Confirm(data))
	{
		RepairAPI(4, RealWPM);
		res = RealWPM(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesWritten);
		HookAPI(4, RealWPM, MyWriteProcessMemory);
	}

	return res;
}


// CreateProcessW
BOOL WINAPI MyCreateProcess(
    __in_opt    LPCWSTR lpApplicationName,
    __inout_opt LPWSTR lpCommandLine,
    __in_opt    LPSECURITY_ATTRIBUTES lpProcessAttributes,
    __in_opt    LPSECURITY_ATTRIBUTES lpThreadAttributes,
    __in        BOOL bInheritHandles,
    __in        DWORD dwCreationFlags,
    __in_opt    LPVOID lpEnvironment,
    __in_opt    LPCWSTR lpCurrentDirectory,
    __in        LPSTARTUPINFOW lpStartupInfo,
    __out       LPPROCESS_INFORMATION lpProcessInformation
    )
{
	int res = 0;
	char temp[1024] = { 0 };
	wcstombs(temp, lpApplicationName, 1024);

	SecureZeroMemory(&data, sizeof(data));

	strcpy(data.apiName, "CreateProcess");

	strcpy(data.msg1, temp);
	strcat(data.msg1, " (Application name)");

	wcstombs(temp, lpApplicationName, 1024);
	strcpy(data.msg2, temp);
	strcat(data.msg2, " (Command line)");

	wcstombs(temp, lpCurrentDirectory, 1024);
	strcpy(data.msg3, temp);
	strcat(data.msg3, " (Current directory)");
	
	if (Confirm(data))
	{
		RepairAPI(3, RealCreateProcess);
		res = RealCreateProcess(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, 
			bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
		HookAPI(2, RealCreateProcess, MyCreateProcess);
	}

	return res;
}

// NtTerminateProcess
NTSTATUS WINAPI MyTerminateProcess(HANDLE hProcess, NTSTATUS ExitStatus)
{
	NTSTATUS res = 0xC0000022;

	SecureZeroMemory(&data, sizeof(DATA));
	
	char x[80] = { 0 };

	strcpy(data.apiName, "TerminateProcess");
	
	sprintf(x, "%x (Process handle)", hProcess);
	strcpy(data.msg1, x);

	sprintf(x, "%u (Exit status)", ExitStatus);
	strcpy(data.msg2, x);
	
	if (Confirm(data))
	{
		RepairAPI(2, RealTerminateProcess);
		res = RealTerminateProcess(hProcess, ExitStatus);
		HookAPI(2, RealTerminateProcess, MyTerminateProcess);
	}

	return res;
}

// MessageBoxW
int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType)
{

	int res = 0; // Error code for MessageBoxW
	char temp[1024] = { 0 };
	wcstombs(temp, lpText, 1024);
	
	SecureZeroMemory(&data, sizeof(DATA));

	// API name
	strcpy(data.apiName, "MessageBoxW");
	
	char x[80] = { 0 };

	// Params
	sprintf(x, "%x (HWND)", hWnd);
	strcpy(data.msg1, x);

	strcpy(data.msg2, temp);
	strcat(data.msg2, " (Text)");

	wcstombs(temp, lpCaption, 1024);
	strcpy(data.msg3, temp);
	strcat(data.msg3, " (Caption)");

	sprintf(x, "%u (uType)", uType);

	strcpy(data.msg4, x);
	
	if (Confirm(data))
	{
		RepairAPI(1, RealMBW);
		res = RealMBW(hWnd, lpText, lpCaption, uType);
		HookAPI(1, RealMBW, MyMessageBoxW);
	}

	return res; 
}

BOOL Confirm(DATA data)
{
	char recv[16] = { 0 };

	if (SendData(&data, sizeof(data)))
	{
		while (true)
		{
			ReadData(recv, 16);

			if (strcmp(recv, "y") == 0)
			{
				return 1;
			}
			else if (strcmp(recv, "n") == 0)
			{
				return 0;
			}

			Sleep(10);
		}
	}
}

BOOL SendData(LPVOID data, DWORD size)
{
	DWORD out;
	return WriteFile(hPipeSend, data, size, &out, NULL);
}

BOOL ReadData(OUT LPVOID data, DWORD size)
{
	DWORD out;
	return ReadFile(hPipeRecv, data, size, &out, NULL);
}

void DoStuff()
{
	hPipeRecv = CreateFileA("\\\\.\\pipe\\ChintuR", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, NULL, NULL);
	if (hPipeSend)
	{
		HookAPI(1, RealMBW, MyMessageBoxW); // MessageBoxW
		HookAPI(2, RealTerminateProcess, MyTerminateProcess); // TerminateProcess
		HookAPI(3, RealCreateProcess, MyCreateProcess); // CreateProcess
		HookAPI(4, RealWPM, MyWriteProcessMemory); // WriteProcessMemory
		HookAPI(5, RealRPM, MyReadProcessMemory); // ReadProcessMemory
	} 
}

void Clean()
{
	CloseHandle(hPipeSend);
	CloseHandle(hPipeRecv);
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
	switch (fdwReason)
	{
		case DLL_PROCESS_ATTACH:
			dllHandle = hinstDLL;
			hPipeSend = CreateFileA("\\\\.\\pipe\\ChintuS", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, NULL, NULL);
			CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)DoStuff, NULL, NULL, NULL);
			break;

	}

	return true;
}